package io.github.echarts.model.adapter;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import io.github.echarts.model.ChartModel;
import io.github.echarts.model.context.ConfigurationContext;
import io.github.echarts.model.coordinate.CoordinateSystem;
import io.github.echarts.model.coordinate.CoordinateSystemManager;
import io.github.echarts.model.coordinate.CoordinateSystemType;
import io.github.echarts.model.coordinate.DataRange;
import io.github.echarts.model.coordinate.cartesian.CartesianCoordinateSystem;
import io.github.echarts.model.coordinate.cartesian.DefaultCartesianCoordinateSystem;
import io.github.echarts.model.coordinate.cartesian.CartesianCoordinateTransformer;
import io.github.echarts.model.coordinate.axis.AxisModel;
import io.github.echarts.model.geometry.Rectangle;
import io.github.echarts.model.series.SeriesDataManager;
import io.github.echarts.option.EChartOption;

/**
 * 坐标系适配器。
 * 从配置选项中提取坐标系相关配置，并转换为内部坐标系模型。
 */
public class CoordinateSystemAdapter {
    
    /**
     * 适配坐标系。
     *
     * @param option 包含坐标系配置的EChartOption
     * @param model 目标ChartModel
     * @param context 配置上下文
     */
    public void adaptCoordinateSystems(EChartOption option, ChartModel model, ConfigurationContext context) {
        // 获取坐标系管理器
        CoordinateSystemManager manager = model.getCoordinateSystemManager();
        
        // 获取布局管理器计算的网格区域
        Rectangle gridArea = getLayoutGridArea(model);
        
        // 如果没有布局计算的网格区域，使用默认区域
        if (gridArea == null) {
            gridArea = new Rectangle(50, 50, model.getWidth() - 100, model.getHeight() - 100);
        }
        
        // 处理直角坐标系（grid）
        io.github.echarts.option.component.Grid grid = option.getGrid();
        
        // 获取X轴和Y轴配置
        io.github.echarts.option.component.Axis xAxisOption = option.getXAxis();
        io.github.echarts.option.component.Axis yAxisOption = option.getYAxis();
        
        // 确保坐标轴配置存在
        if (xAxisOption == null) {
            xAxisOption = new io.github.echarts.option.component.Axis();
            xAxisOption.setType("category");
            xAxisOption.setShow(true);
        }
        
        if (yAxisOption == null) {
            yAxisOption = new io.github.echarts.option.component.Axis();
            yAxisOption.setType("value");
            yAxisOption.setShow(true);
        }
        
        // 确保坐标轴线、标签和刻度显示
        ensureAxisVisualElements(xAxisOption);
        ensureAxisVisualElements(yAxisOption);
        
        if (grid != null) {
            // 创建坐标系并关联坐标轴
            String cartesianId = manager.createCoordinateSystem(
                CoordinateSystemType.CARTESIAN, gridArea, grid);
            
            // 获取创建的坐标系
            CoordinateSystem cartesianSystem = manager.getCoordinateSystem(cartesianId);
            
            // 如果是笛卡尔坐标系，设置X轴和Y轴
            if (cartesianSystem instanceof io.github.echarts.model.coordinate.cartesian.DefaultCartesianCoordinateSystem) {
                io.github.echarts.model.coordinate.cartesian.DefaultCartesianCoordinateSystem cartesian = 
                    (io.github.echarts.model.coordinate.cartesian.DefaultCartesianCoordinateSystem) cartesianSystem;
                
                // 设置坐标轴
                cartesian.setXAxis(xAxisOption);
                cartesian.setYAxis(yAxisOption);
                
                // 为类别轴设置默认类别数据（如果没有设置）
                setupCategoryData(xAxisOption, option);
                
                // 初始化坐标系
                cartesian.initialize();
            }
            
            // 设为主坐标系
            manager.setMainCoordinateSystem(cartesianSystem);
        } else {
            // 如果没有明确配置，确保创建默认坐标系
            ensureDefaultCoordinateSystem(model, gridArea);
            
            // 获取默认坐标系
            CoordinateSystem defaultSystem = model.getMainCoordinateSystem();
            
            // 如果是笛卡尔坐标系，设置X轴和Y轴
            if (defaultSystem instanceof io.github.echarts.model.coordinate.cartesian.DefaultCartesianCoordinateSystem) {
                io.github.echarts.model.coordinate.cartesian.DefaultCartesianCoordinateSystem cartesian = 
                    (io.github.echarts.model.coordinate.cartesian.DefaultCartesianCoordinateSystem) defaultSystem;
                
                // 设置坐标轴
                cartesian.setXAxis(xAxisOption);
                cartesian.setYAxis(yAxisOption);
                
                // 为类别轴设置默认类别数据（如果没有设置）
                setupCategoryData(xAxisOption, option);
                
                // 初始化坐标系
                cartesian.initialize();
            }
        }
        
        // 处理雷达图坐标系
        io.github.echarts.option.component.Radar radar = option.getRadar();
        if (radar != null) {
            // 雷达图使用不同的区域，通常是圆形或多边形区域
            // 可以使用gridArea，但可能需要调整为正方形
            Rectangle radarArea = makeSquareArea(gridArea);
            manager.createCoordinateSystem(CoordinateSystemType.RADAR, radarArea, radar);
        }
        
        // 为每个系列关联对应的坐标系实例
        new SeriesAdapter().linkSeriesToCoordinateSystems(model);
        
        // 同步坐标系与数据范围
        syncCoordinateSystemsWithData(model);
        
        // 将网格区域存储到模型中，以便后续使用
        model.setGridArea(gridArea);
    }
    
    /**
     * 确保模型有默认坐标系
     * 
     * @param model 图表模型
     * @param area 布局区域
     */
    public void ensureDefaultCoordinateSystem(ChartModel model, Rectangle area) {
        // 如果没有主坐标系，创建默认的笛卡尔坐标系
        if (model.getMainCoordinateSystem() == null) {
            // 确保区域不为null
            if (area == null) {
                area = new Rectangle(50, 50, model.getWidth() - 100, model.getHeight() - 100);
            }
            
            // 创建默认坐标系并设置为主坐标系
            String defaultId = model.getCoordinateSystemManager().ensureDefaultCoordinateSystem(area);
            CoordinateSystem defaultCS = model.getCoordinateSystemManager().getCoordinateSystem(defaultId);
            model.setMainCoordinateSystem(defaultCS);
        }
    }
    
    /**
     * 同步坐标系与数据范围
     * 确保坐标系的轴模型获得正确的数据范围
     * 
     * @param model 图表模型
     */
    public void syncCoordinateSystemsWithData(ChartModel model) {
        SeriesDataManager seriesDataManager = model.getSeriesDataManager();
        if (seriesDataManager == null) {
            return;
        }
        
        // 确保数据处理已完成
        seriesDataManager.processData();
        seriesDataManager.calculateDataRanges();
        
        // 为每个坐标系应用相应的数据范围
        for (CoordinateSystem cs : model.getCoordinateSystems()) {
            // 获取该坐标系对应的数据范围
            String csId = cs.getId();
            DataRange range = seriesDataManager.getDataRange(csId);
            
            // 如果找到了数据范围，使用坐标系的专用方法应用它
            if (range != null) {
                cs.applyDataRange(range);
            }
        }
    }
    
    /**
     * 从布局管理器获取计算好的网格区域
     * 
     * @param model 图表模型
     * @return 网格区域，如果未计算则返回null
     */
    private Rectangle getLayoutGridArea(ChartModel model) {
        // 获取模型中的布局管理器
        io.github.echarts.model.layout.LayoutManager layoutManager = model.getLayoutManager();
        if (layoutManager != null) {
            return layoutManager.getContentArea();
        }
        
        // 尝试直接获取模型的网格区域
        return model.getGridArea();
    }
    
    /**
     * 将矩形区域转换为正方形（用于雷达图等需要等比例区域的坐标系）
     * 
     * @param rect 原始矩形区域
     * @return 正方形区域
     */
    private Rectangle makeSquareArea(Rectangle rect) {
        // 使用较小的边长创建正方形
        double size = Math.min(rect.getWidth(), rect.getHeight());
        
        // 保持中心点不变
        double centerX = rect.getX() + rect.getWidth() / 2;
        double centerY = rect.getY() + rect.getHeight() / 2;
        
        // 创建新的正方形区域
        return new Rectangle(
            centerX - size / 2, // 左侧
            centerY - size / 2, // 顶部
            size,              // 宽度
            size               // 高度
        );
    }
    
    /**
     * 确保坐标轴的视觉元素（轴线、标签、刻度）可见
     * 
     * @param axis 坐标轴配置
     */
    private void ensureAxisVisualElements(io.github.echarts.option.component.Axis axis) {
        // 确保轴线可见
        if (axis.getAxisLine() == null) {
            io.github.echarts.option.component.axis.AxisLine axisLine = new io.github.echarts.option.component.axis.AxisLine();
            axisLine.setShow(true);
            axis.setAxisLine(axisLine);
        }
        
        // 确保刻度可见
        if (axis.getAxisTick() == null) {
            io.github.echarts.option.component.axis.AxisTick axisTick = new io.github.echarts.option.component.axis.AxisTick();
            axisTick.setShow(true);
            axis.setAxisTick(axisTick);
        }
        
        // 确保标签可见
        if (axis.getAxisLabel() == null) {
            io.github.echarts.option.component.axis.AxisLabel axisLabel = new io.github.echarts.option.component.axis.AxisLabel();
            axisLabel.setShow(true);
            axis.setAxisLabel(axisLabel);
        }
    }
    
    /**
     * 获取对象的长度(如果是数组或集合)
     * 
     * @param obj 要检查的对象
     * @return 长度，如果不是数组或集合则返回0
     */
    private int getObjectLength(Object obj) {
        if (obj == null) {
            return 0;
        }
        
        if (obj.getClass().isArray()) {
            return Array.getLength(obj);
        }
        
        if (obj instanceof List) {
            return ((List<?>) obj).size();
        }
        
        return 0;
    }
    
    /**
     * 将Object安全地转换为Object[]数组
     * 
     * @param data 可能是数组的对象
     * @return 转换后的Object[]数组，如果无法转换则返回空数组
     */
    private Object[] toObjectArray(Object data) {
        if (data == null) {
            return new Object[0];
        }
        
        // 如果已经是Object[]，直接返回
        if (data instanceof Object[]) {
            return (Object[]) data;
        }
        
        // 如果是其他类型的数组，转换为Object[]
        if (data.getClass().isArray()) {
            int length = Array.getLength(data);
            Object[] result = new Object[length];
            for (int i = 0; i < length; i++) {
                result[i] = Array.get(data, i);
            }
            return result;
        }
        
        // 如果是列表，转换为Object[]
        if (data instanceof List) {
            List<?> list = (List<?>) data;
            return list.toArray(new Object[0]);
        }
        
        // 将单个对象包装为数组
        return new Object[] { data };
    }
    
    /**
     * 为类别轴设置默认类别数据
     * 
     * @param xAxisOption X轴配置
     * @param option ECharts配置
     */
    private void setupCategoryData(io.github.echarts.option.component.Axis xAxisOption, EChartOption option) {
        // 如果是类别轴但没有数据
        if ("category".equals(xAxisOption.getType()) && 
            (xAxisOption.getData() == null || getObjectLength(xAxisOption.getData()) == 0)) {
            
            // 从系列数据中提取类别信息
            if (option.getSeries() != null) {
                Object seriesObj = option.getSeries();
                List<String> categories = new ArrayList<>();
                
                if (seriesObj instanceof List) {
                    @SuppressWarnings("unchecked")
                    List<io.github.echarts.option.series.SeriesOption> seriesList = 
                        (List<io.github.echarts.option.series.SeriesOption>) seriesObj;
                    extractCategoriesFromSeries(seriesList, categories);
                } else if (seriesObj instanceof io.github.echarts.option.series.SeriesOption[]) {
                    io.github.echarts.option.series.SeriesOption[] seriesArray = 
                        (io.github.echarts.option.series.SeriesOption[]) seriesObj;
                    for (io.github.echarts.option.series.SeriesOption series : seriesArray) {
                        extractCategoriesFromSingleSeries(series, categories);
                    }
                }
                
                // 如果从数据中提取到类别信息
                if (!categories.isEmpty()) {
                    xAxisOption.setData(categories.toArray());
                } else {
                    // 否则设置默认类别
                    xAxisOption.setData(new String[] {"类别1", "类别2", "类别3", "类别4", "类别5"});
                }
            } else {
                // 如果没有系列数据，设置默认类别
                xAxisOption.setData(new String[] {"类别1", "类别2", "类别3", "类别4", "类别5"});
            }
        }
    }
    
    /**
     * 从系列列表中提取类别信息
     * 
     * @param seriesList 系列列表
     * @param categories 类别集合
     */
    private void extractCategoriesFromSeries(List<io.github.echarts.option.series.SeriesOption> seriesList, List<String> categories) {
        for (io.github.echarts.option.series.SeriesOption series : seriesList) {
            extractCategoriesFromSingleSeries(series, categories);
        }
    }
    
    /**
     * 从单个系列中提取类别信息
     * 
     * @param series 系列配置
     * @param categories 类别集合
     */
    private void extractCategoriesFromSingleSeries(io.github.echarts.option.series.SeriesOption series, List<String> categories) {
        if (series.getData() != null) {
            // 安全地将series.getData()转换为Object[]
            Object[] data = toObjectArray(series.getData());
            for (int i = 0; i < data.length; i++) {
                Object item = data[i];
                String category = "";
                
                if (item instanceof Map) {
                    @SuppressWarnings("unchecked")
                    Map<String, Object> dataMap = (Map<String, Object>) item;
                    if (dataMap.containsKey("name")) {
                        category = String.valueOf(dataMap.get("name"));
                    }
                } else {
                    // 如果没有名称，使用索引作为类别
                    category = "类别" + (i + 1);
                }
                
                if (!category.isEmpty() && !categories.contains(category)) {
                    categories.add(category);
                }
            }
        }
    }
} 